﻿/**********************************************/
/*Project: CRF#                               */
/*Author: Zhongkai Fu                         */
/*Email: fuzhongkai@gmail.com                 */
/**********************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CRFSharp
{
    public class SegCrfTag : CrfTag
    {
        bool use_ne;

        string yname_str;
        string nename_str;

        public SegCrfTag(uint this_max_nbest = Utils.DEFAULT_MAX_NBEST, uint this_crf_max_word_num = Utils.DEFAULT_CRF_MAX_WORD_NUM, uint this_crf_max_word_len = Utils.DEFAULT_CRF_MAX_WORD_LEN)
            : base(max_nbest, crf_max_word_num, crf_max_word_len)
        {
            max_nbest = this_max_nbest;
            crf_max_word_num = this_crf_max_word_num;
            crf_max_word_len = this_crf_max_word_len;

            yname_str = "";
            nename_str = "";

        }

        public int seg_add(ref List<List<string>> row_p)
        {
            return add(ref row_p);
        }

        public int seg_parse()
        {
            return parse();
        }

        public int seg_init_by_model(ref CrfModel this_model)
        {
            int ret = init_by_model(ref this_model);
            if (ret < 0)
            {
                return -1;
            }
            use_ne = false;
            for (int i = 0; i < (int)(ysize); i++)
            {
                yname_str = yname(i);
                if (yname_str.IndexOf('_') > 0)
                {
                    use_ne = true;
                }
            }
            return ret;
        }

        int seg_tag_clear()
        {
            return clear();
        }

        int seg_termbuf_build(ref crf_term_out_t term_buf, int vlevel)
        {
            string t = "";
            int num = 0;
            double weight = 0.0f;
            int term_len = 0;

            term_buf.wordtotallen = 0;
            term_buf.crftermcount = 0;
            uint this_word_num = get_word_num();
            for (int i = 0; i < this_word_num; ++i)
            {
                if (term_len + x_[i][0].Length > Utils.CRF_MAX_WORD_LEN)
                {
                    return -1;
                }

                term_len += (int)x_[i][0].Length;

                yname_str = yname(y(i));
                nename_str = "";
                if (use_ne)
                {
                    int zz = yname_str.IndexOf('_');
                    if (zz > 0)
                    {
                        nename_str = yname_str.Substring(zz + 1);
                    }
                }

                int spos = yname_str.IndexOf('_');
                if (spos < 0)
                {
                    t = yname_str;
                }
                else
                {
                    t = yname_str.Substring(0, spos);
                }

                switch (vlevel)
                {
                    case 0:
                        break;
                    case 1:
                        //对所有词均计算权值
                        weight += prob(i);
                        num++;
                        break;
                    case 2:
                        //只对专名计算权值
                        if (nename_str.Length > 0)
                        {
                            weight += prob(i);
                            num++;
                        }
                        else
                        {
                            weight = 0.0;
                            num = 0;
                        }
                        break;
                }

                if (t == "E" || t == "S" || i == this_word_num - 1)
                {
                    term_buf.crftermlen[term_buf.crftermcount] = term_len;
                    term_buf.crftermoffsets[term_buf.crftermcount] = term_buf.wordtotallen;
                    term_buf.wordtotallen += term_len;
                    term_buf.crfneprop[term_buf.crftermcount].strTag = nename_str;
                    
                    switch (vlevel)
                    {
                        case 0:
                            term_buf.crfneprop[term_buf.crftermcount].iWeight = 0;
                            break;
                        case 1:
                            term_buf.crfneprop[term_buf.crftermcount].iWeight = (int)(weight * 1000 / num);
                            weight = 0.0;
                            num = 0;
                            break;
                        case 2:
                            if (nename_str.Length == 0)
                            {
                                term_buf.crfneprop[term_buf.crftermcount].iWeight = 0;
                                weight = 0.0;
                                num = 0;
                            }
                            else
                            {
                                term_buf.crfneprop[term_buf.crftermcount].iWeight = (int)(weight * 1000 / num);
                                weight = 0.0;
                                num = 0;
                            }
                            break;
                    }

                    term_buf.crftermcount++;
                    term_len = 0;
                }
            }
            return 0;
        }


        public int seg_output(ref crf_out_t pout)
        {
            int n = 0;
            int ret = 0;

            if (max_nbest == 1 || (get_nbest() == 1))
            {  //当只需要最优结果并且无需概率计算时,并不使用next
                pout.nbest = 1;

                crf_term_out_t term_buf = pout.term_buf[0];
                ret = seg_termbuf_build(ref term_buf, (int)get_vlevel());
                pout.term_buf[0] = term_buf;
                if (ret < 0)
                {
                    return -1;
                }
            }
            else
            {
                int max_next_time = (int)get_nbest();
                if (!use_ne && get_word_num() < 5)
                {
                    int pow_next_time = (int)(Math.Pow(2, (get_word_num() - 1)));
                    if (pow_next_time < max_next_time)
                    {
                        max_next_time = pow_next_time;
                    }
                }
                for (n = 0; n < max_next_time; ++n)
                {
                    ret = next();
                    if (ret < 0)
                    {
                        break;
                    }

                    crf_term_out_t term_buf = pout.term_buf[n];
                    ret = seg_termbuf_build(ref term_buf, (int)get_vlevel());
                    pout.term_buf[n] = term_buf;
                    if (ret < 0)
                    {
                        return -1;
                    }
                }
                pout.nbest = n;
            }

            return 0;
        }
    }
}
